UnityのEditorのUpdateが走り出すのは具体的にいつからなのか
概要
Unityのエディタのなかで、Updateを使用したツールを作っていた際に気になったので調べた。
該当のAPIはこれ。
UnityEditor.EditorApplication.update
確認を行った環境は以下。
Mac OS 10.10, 10.9
Unity 4.3.7 ~ 5.0.0(beta)
実行開始タイミング
最初のEditorのUpdateが走るのは、「InitializeOnLoad よりも後」だった。
InitializeOnLoad を付けておいたstaticクラスのコンパイルが終わり、動作が開始した際には、まだUpdateは走っていない。
InitializeOnLoad 内ではすでに走っているのかと思っていた。
公式の死霊に照らし合わせると、
http://docs.unity3d.com/412/Documentation/ScriptReference/index.Script_compilation_28Advanced29.html
Editor内でのコードのコンパイルが行われるのはコンパイル行程の最後、
1.Standard系がコンパイルされる
2.Standard Assets/Editor 系がコンパイルされる
3.Editor以外がコンパイルされる
4.Editorがコンパイルされる
の、4番よりもさらにあと、コンパイルが終わり、InitializeOnLoad が走っているタイミングでもまだ実行されていない。
たとえば InitializeOnLoad で処理を開始した場合、まだコンパイル行程が終わっておらず、ログにも「compile終わったわ~~」とか書かれていないので、
ああなるほどそういうこともあるんだなという感じ。
ちなみに最初のUpdateがはしるのは、ログでいうと下記の箇所だった。
IsUpdateRunning?:False
UnityEngine.Debug:Internal_Log(Int32, String, Object)
UnityEngine.Debug:Log(Object)
SublimeSocketClient:StartConnect() (at Assets/SublimeSocketAsset/Editor/Scripts/SublimeSocketClient.cs:442)
SublimeSocketClient:AutoConnect(String, String) (at Assets/SublimeSocketAsset/Editor/Scripts/SublimeSocketClient.cs:192)
SublimeSocketClient:Automate() (at Assets/SublimeSocketAsset/Editor/Scripts/SublimeSocketClient.cs:138)
UnityEditorEventHandler:.cctor() (at Assets/SublimeSocketAsset/Editor/Scripts/UnityEditorEventHandler.cs:13)
System.Runtime.CompilerServices.RuntimeHelpers:RunClassConstructor(IntPtr)
System.Runtime.CompilerServices.RuntimeHelpers:RunClassConstructor(RuntimeTypeHandle) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.CompilerServices/RuntimeHelpers.cs:101)
UnityEditor.EditorAssemblies:RunClassConstructors()
UnityEditor.EditorAssemblies:SetLoadedEditorAssemblies(Assembly[])
(Filename: Assets/SublimeSocketAsset/Editor/Scripts/SublimeSocketClient.cs Line: 442)
Requesting http://update.unity3d.com/4.3/ivy.xml
Downloading into /var/folders/8r/04ts4kp16yv700w9kdgzpqb80000gn/T/unity/50acea4d-04e3-42c3-8ab1-454a6ea089a9/ivy.xml
----- Total AssetImport time: 0.161818s, Asset Import: 0.000000s, CacheServerIntegrate: 0.000000s, CacheServer Download: 0.000000s [0 B, nan mb/s], CacheServer Hashing: 0.000304s [0.9 KB, 2.780007 mb/s]
Mono: successfully reloaded assembly
- Completed reload, in 1.966 seconds
first update!
太字のところに注目、
IsUpdateRunning?:False は InitializeOnLoad で着火しているメソッドの中でupdateにセットしたイベント内でのログ。
first update! が実際に初めてUpdateが走った箇所。
Completeのログが出るまでは、Updateは走らないぽい。
時系列でまとめると下記のような感じ。
・~ Editor Scriptのコンパイル完了、DLLのロード開始
・InitializeOnLoad Attributeがついてるメソッドの着火
・それらの完了
・正式なコンパイル完了
・Update起動開始
は~~~Updateの特性を考えるとしょうがないのか。
例えば複数の「Updateに依存するEditorScript」があった場合、Updateが走り出したタイミングでDLLのロードが終わっていないと
相互依存できなくなったりカオスになったりでメチャクチャ困るわけだ。
正直Updateが走り出してからInitializeOnLoadが走ってくれると嬉しかった。
というかその場合は、Updateが走り出してから走らせるようにすればまあそれでいいんだな。
最初のUpdateで一度だけ走って消えるようなハンドラでいいよね。
UniRxを使ってエディタでのスクリプトを書く場合
ちなみに便利で素敵なUniRxを使ってEditorのコードを書く場合、
UniRx
https://github.com/neuecc/UniRx
http://u3d.as/content/neuecc/uni-rx-reactive-extensions-for-unity/7tT
UniRxがエディタ上でCoroutineとか回すのに使っているのは上記の EditorApplication.update なので、
initializeOnLoad 中のメソッドでセットしたりStartCoroutineしようとしても、即着火はしない。
実際にはInitializeOnLoad のブロックが終了したあとになってはじめてコンパイル完了のタイミングを迎え、
Updateも走るようになるので、そこで初めて着火する。
というかUniRxの挙動のおかげで、Updateの開始位置をまともに調べるに至った。
勉強になった。
おまけ:Updateが、、、死んでる、、、!?? っていう地獄のような話
とあるユーザーさんからのご連絡で判明したんだけど、
Updateに依存したコードを書いてて、着火しない、っていう事態があったそうな。
状況を聞いた限りだと、
・Mac版Unityで発生(Winで起きるかはしらない)
・UnityEditorを起動、プロジェクトを開いているのをチラ見したあと、UnityEditor以外のアプリケーションをアクティブにしていた
・バックグラウンドでコンパイルが完了するのを目視
っていう状態で、EditorApplication.update が一回も発生しない、という状態が発生したとのこと。
んでじゃあ再現してみるべ、って試してみたら、下記手順で再現できた。
1.MonoDevelopとかエディタでコードを書く
2.保存
3.コンパイルさせるためにUnityEditorをActiveにする(ウインドウとかをマウスクリックするだけでOK)
4.MonoDevelopとかエディタにもどる(ウインドウとかをマウスクリックするだけでOK)
1~4を高速で行うと、コンパイル完了してもUpdateが発生しない場合がある。
試したところで20回に一回くらいだった。
すげー頑張った。
確かにコンパイル完了してるはずなんだけど、Updateが一度も走らない。
ちなみに心配になってFocusしにいくとUpdateは元気に走り出す。
推察するに、Unityにフォーカスが移った時、2段階以上の予備動作時間があるみたいだ。
0.focus ->
1.コンパイル開始の条件を満たす ->
2.stay focus ->
3.Updateが走り出すための条件を満たす
みたいな。
日照時間みたいなものかな、、、
3の条件を満たす時間的な要因はよくわかっていない。
あとたぶんハンドラとかも無いと思う。
あ、ログに何か出るとかはあるかもしれない、、し、無いかもしれない。
あれか。
君はじっと眺めてないと働かない子か。まあいいんだが。
ちなみにコンパイル時間 = プロジェクト規模との相関は不明。
あと、コマンドラインから起動した場合はどうなっちゃうんだ?
AssetRailsでも利用してないから気にはなる。
というわけで、日照時間が極端に短いと、コンパイル完了後にUpdateが走り出さないという事象を確認した。
Unity氏~~~~ もうめんどうくさいからコンパイル開始APIくだされ~~~~